"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MySql = void 0;
const dbClient_1 = require("./dbClient");
const common_1 = require("../common");
const mysql = require('mysql');
class MySqlTransaction extends dbClient_1.Transaction {
    constructor(connection) {
        super();
        this.connection = connection;
    }
    async oneOrNone(sql) {
        const result = await this.query(sql);
        return result ? ((0, common_1.isArray)(result) ? result[0] : result) : null;
    }
    async one(sql) {
        const result = await this.query(sql);
        if (!result) {
            throw new dbClient_1.DbClientNotFoundError();
        }
        return (0, common_1.isArray)(result) ? result[0] : result;
    }
    async query(sql) {
        return new Promise((resolve, reject) => {
            this.connection.query(sql, (error, results) => {
                if (error) {
                    return reject(error);
                }
                resolve(results);
            });
        });
    }
    async none(sql) {
        await this.query(sql);
    }
}
class MySql extends dbClient_1.DbClient {
    constructor({ host, port, database, user, password, connectionLimit }) {
        super({ host, port, database, user, password });
        this.connectionLimit = connectionLimit;
    }
    setConnection(connection) {
        this.pool = connection;
    }
    async oneOrNone(sql, transaction) {
        const executor = transaction || this;
        const result = await executor.query(sql);
        return result ? ((0, common_1.isArray)(result) ? result[0] : result) : null;
    }
    async one(sql, transaction) {
        const executor = transaction || this;
        const result = await executor.query(sql);
        if (!result) {
            throw new dbClient_1.DbClientNotFoundError();
        }
        return (0, common_1.isArray)(result) ? result[0] : result;
    }
    async query(sql, transaction) {
        return new Promise(async (resolve, reject) => {
            let connection;
            let shouldRelease = false;
            try {
                if (transaction) {
                    connection = transaction.connection;
                }
                else {
                    connection = await this.getConnection();
                    shouldRelease = true;
                }
                connection.query(sql, (error, results) => {
                    if (shouldRelease) {
                        connection.release();
                    }
                    if (error) {
                        return reject(error);
                    }
                    resolve(results);
                });
            }
            catch (error) {
                if (shouldRelease && connection) {
                    connection.release();
                }
                reject(error);
            }
        });
    }
    async none(sql, transaction) {
        await this.query(sql, transaction);
    }
    async tx(func) {
        return new Promise(async (resolve, reject) => {
            const connection = await this.getConnection();
            connection.beginTransaction(async (transactionErr) => {
                if (transactionErr) {
                    connection.release();
                    return reject(transactionErr);
                }
                const transaction = new MySqlTransaction(connection);
                try {
                    const result = await func(transaction);
                    connection.commit((commitError) => {
                        connection.release();
                        if (commitError) {
                            return reject(commitError);
                        }
                        resolve(result);
                    });
                }
                catch (error) {
                    console.error('Transaction error:', error);
                    connection.rollback(() => {
                        connection.release();
                        reject(error);
                    });
                }
            });
        });
    }
    async connect() {
        const { host, port, database, user, password, connectionLimit } = this;
        this.pool = mysql.createPool({
            host,
            port,
            database,
            user,
            password,
            connectionLimit: connectionLimit || 10,
            acquireTimeout: 60000,
            timeout: 60000,
            reconnect: true
        });
    }
    async getConnection() {
        return new Promise((resolve, reject) => {
            this.pool.getConnection((err, connection) => {
                if (err) {
                    return reject(err);
                }
                resolve(connection);
            });
        });
    }
    insertSql(data, cs, tableConfig) {
        const columnNames = cs.columns.map((it) => it.name);
        const values = columnNames.map((it) => {
            return this.escapeValue(data[it]);
        });
        return `INSERT INTO ${tableConfig.table} (${columnNames.join(',')}) VALUES (${values.join(',')})`;
    }
    updateSql(data, cs, tableConfig) {
        const setClause = cs.columns.map((it) => {
            return `${it.name} = ${this.escapeValue(data[it.name])}`;
        }).join(',');
        return `UPDATE ${tableConfig.table} SET ${setClause}`;
    }
}
exports.MySql = MySql;
